import * as vscode from "vscode";
import { getBox3MapList, ExtendedQuickPickItem } from "@ap/user/map/getMapList";
import { CommandId } from "@ap/command";
import path from "path";
import { $context } from "@ap/extension";

// 定义一个枚举类型 nodeImg，用于集中管理节点图像的文件名
enum nodeImg {
  "hourglass_node.svg", // 沙漏节点的图像文件名
  "success.svg", // 成功状态的图像文件名
  "warn_node.svg", // 警告节点的图像文件名
}
/**
 * 表示 Visual Studio Code 中地图树视图的一个项目。
 * 继承 vscode.TreeItem 并添加特定于应用程序的属性，如 children。
 */
class MapTreeItem extends vscode.TreeItem {
  children?: MapTreeItem[];

  /**
   * 构造 MapTreeItem 的实例。
   */
  constructor(
    public readonly label: string,
    public readonly description: string,
    public readonly tooltip: string,
    public readonly collapsibleState: vscode.TreeItemCollapsibleState,
    public readonly mapId: string,
    public readonly editHash: string,
    public readonly playHash: string,
    public readonly iconPath?: vscode.Uri,
  ) {
    super(label, collapsibleState);
  }
}

/**
 * 为 Visual Studio Code 中的地图树视图提供数据。
 * 实现 vscode.TreeDataProvider 接口以提供 getTreeItem、getChildren 和 refresh 功能。
 */
export default class MapTreeDataProvider
  implements vscode.TreeDataProvider<MapTreeItem>
{
  // 用于信号树数据已更改的 EventEmitter。
  private _onDidChangeTreeData: vscode.EventEmitter<MapTreeItem | undefined> =
    new vscode.EventEmitter<MapTreeItem | undefined>();

  // 当树数据发生变化时触发的事件。
  readonly onDidChangeTreeData: vscode.Event<MapTreeItem | undefined> =
    this._onDidChangeTreeData.event;

  /**
   * 获取给定元素的树项。
   * @param element 要获取树项的元素。
   * @returns 给定元素的树项。
   */
  getTreeItem(element: MapTreeItem): vscode.TreeItem {
    return element;
  }

  /**
   * 异步获取给定元素的子项。
   * 如果未指定元素，则获取树的根元素。
   * @param element 要获取其子项的元素。
   * @returns 一个 Promise，解析为表示子项的 MapTreeItem 数组。
   */
  async getChildren(element?: MapTreeItem | undefined): Promise<MapTreeItem[]> {
    if (!element) {
      // 如果没有提供元素，则从地图列表构建树结构。
      const mapData = this.buildTree(await getBox3MapList());
      return mapData;
    }
    // 返回指定元素的子项（如果存在）。
    return element.children || [];
  }

  /**
   * 从扁平的地图数据列表构造树结构。
   * @param data 表示地图数据的扩展快速选择项列表。
   * @returns 表示构造的树的根节点的 MapTreeItem 数组。
   */
  private buildTree(data: ExtendedQuickPickItem[]): MapTreeItem[] {
    return data.map((item) => {
      let reason = "";
      if (item.reason) {
        for (const item2 of item.reason) {
          reason += item2 + "\n";
        }
        reason = "审核驳回原因：" + reason;
      }
      const treeItem = new MapTreeItem(
        item.label.trim(),
        String(item.description) +
          (item.publishedVersionId ? " V" + item.publishedVersionId : ""),
        reason + item.detail,
        item.subMaps && item.subMaps.length > 1
          ? vscode.TreeItemCollapsibleState.Collapsed
          : vscode.TreeItemCollapsibleState.None,
        String(item.description),
        item.editHash,
        item.playHash,
        item.auditStatus !== null
          ? vscode.Uri.file(
              path.join(
                $context.extensionPath,
                "image",
                nodeImg[item.auditStatus],
              ),
            )
          : item.reason
            ? vscode.Uri.file(
                path.join($context.extensionPath, "image", nodeImg[2]),
              )
            : undefined,
      );
      if (item.subMaps && item.subMaps.length > 1) {
        // 递归构造具有 subMaps 的项目的子节点。
        treeItem.children = this.buildTree2(item.subMaps);
      }
      return treeItem;
    });
  }

  /**
   * 从子地图数据列表构造树结构。
   * @param data 表示子地图数据的记录列表。
   * @returns 表示构造的树节点的 MapTreeItem 数组。
   */
  private buildTree2(data: Record<string, any>[]): MapTreeItem[] {
    let data2 = data.map((item) => {
      const treeItem = new MapTreeItem(
        item.name.trim(),
        String(item.id),
        item.detail ?? "",
        vscode.TreeItemCollapsibleState.None,
        String(item.id),
        item.editHash,
        item.playHash,
      );
      return treeItem;
    });
    delete data2[0];
    return data2;
  }

  /**
   * 刷新树数据，导致树视图重新获取数据。
   */
  refresh(): void {
    this._onDidChangeTreeData.fire(undefined);
  }
}
